#include "camera.h"

#define CAMERA_ANIMATION_MAX_TIME	30

/**
 * Zwraca macierz widoku na podstawie trybu kamery i kierunku
 */
Matrix Camera::getTransformationByMode(Mode mode, Direction direction) const
{
	Vector camPos;
	switch(direction)
	{
	case North:
		camPos = Vector(0, 1, -1);
		break;
	case East:
		camPos = Vector(-1, 1, 0);
		break;
	case South:
		camPos = Vector(0, 1, 1);
		break;
	case West:
		camPos = Vector(1, 1, 0);
		break;
	};

	if(!refNode)
		return Matrix::cameraLookAt(
			Vector(0, 1, -1),
			Vector(0, 0, 0),
			Vector(0, 1, 0));

	Vector base = refNode->getAbsoluteTransformation().getTranslation();

	switch(mode)
	{
	case Normal:
		return Matrix::cameraLookAt(
			base + camPos * 0.5f,
			base,
			Vector(0, 1, 0));
	case CloseUp:
		return Matrix::cameraLookAt(
			base + camPos * 0.2f,
			base,
			Vector(0, 1, 0));
	case SkyCamera:
		return Matrix::cameraLookAt(
			base + camPos,
			base,
			Vector(0, 1, 0));
	}
	return Matrix::identity();
}

/**
 * Zwraca macierz widoku na podstawie trybu kamery i klatki animacji
 */
Matrix Camera::getAnimatedTransformation()
{
	if(animationTime < 0)
		return getTransformationByMode(mode, direction);
	return animationBeginTransformation.interpolate(
		getTransformationByMode(mode, direction), 1.0f - (animationTime / ((float)CAMERA_ANIMATION_MAX_TIME)));
}

/**
 * Rozpoczyna plynne przejscie kamery
 */
void Camera::switchToMode(Mode m, Direction d)
{
	if(animationTime >= 0)
		return;

	animationBeginTransformation = getAnimatedTransformation();
	animationTime = 0;
	mode = m;
	direction = d;
}

/**
 * Inkrementuje klatke animacji kamery
 */
void Camera::animationStep()
{
	if(animationTime >= 0)
	{
		animationTime++;

		if(animationTime >= CAMERA_ANIMATION_MAX_TIME)
		{
			animationTime = -1;
		}

	}
}

/**
 * Zwraca wektor jednostkowy wskazujacy kierunek 'na wprost'.
 * Wektor ten zalezy tylko od kierunku kamery.
 */
Vector Camera::getForwardVector() const
{
	switch(direction)
	{
	case North:
		return Vector(0, 0, 1);
	case East:
		return Vector(1, 0, 0);
	case South:
		return Vector(0, 0, -1);
	case West:
		return Vector(-1, 0, 0);
	};
	return Vector(0, 0, 0);
}

/**
 * Zwraca wektor jednostkowy wskazujacy kierunek 'na prawo'.
 * Wektor ten zalezy tylko od kierunku kamery.
 */
Vector Camera::getRightTurnVector() const
{
	switch(direction)
	{
	case North:
		return Vector(1, 0, 0);
	case East:
		return Vector(0, 0, -1);
	case South:
		return Vector(-1, 0, 0);
	case West:
		return Vector(0, 0, 1);
	};
	return Vector(0, 0, 0);
}
